package top.lshaci.learning.nio;

import cn.hutool.core.util.StrUtil;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;

/**
 * NioServer
 *
 * @author lshaci
 * @since 1.0.0
 */
public class NioServer {

    public static void main(String[] args) throws IOException {
        // 创建一个ServerSocketChannel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 创建一个选择器
        final Selector selector = Selector.open();
        // 监听6666端口
        serverSocketChannel.bind(new InetSocketAddress(6666));
        // 设置为非阻塞
        serverSocketChannel.configureBlocking(false);

        // 注册到selector上, 关心事件为 接收到连接
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        System.err.println("服务端启动在6666端口...");
        // 循环等待客户端连接
        while (true) {
            // 等待1秒，判断是否有事件发生
            if (selector.select(1000) == 0) {
//                System.err.println("等待了1S，无连接");
                continue;
            }

            // 获取到相关的SelectionKey
            final Set<SelectionKey> selectionKeys = selector.selectedKeys();
            final Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
            while (keyIterator.hasNext()) {
                final SelectionKey selectionKey = keyIterator.next();
                if (selectionKey.isAcceptable()) {
                    // 给客户端生成一个 SocketChannel
                    final SocketChannel socketChannel = serverSocketChannel.accept();
                    System.err.println("客户端连接成功。。。" + socketChannel.getRemoteAddress());
                    // 指定为非阻塞
                    socketChannel.configureBlocking(false);
                    // 将 socketChannel 注册到 selector， 并指定关注时间为 读，同时给 Channel 关联一个 byteBuffer
                    socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(8192));
                } else if (selectionKey.isReadable()) {
                    final SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    final ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment();

                    socketChannel.read(byteBuffer);
                    System.err.println(StrUtil.format(
                            "接收到数据 => RemoteAddress: {}, Data: {}",
                            socketChannel.getRemoteAddress(),
                            StrUtil.str(byteBuffer.array(), Charset.defaultCharset())
                            )
                    );
                    socketChannel.close();
                }
                keyIterator.remove();
            }
        }
    }


}
